#ifndef __NET_SERVER_H__
#define __NET_SERVER_H__

#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <thread>

#include <boost/asio.hpp>
#include <boost/logic/tribool.hpp>

#include <google/protobuf/message.h>

#include "common/base/manager.h"
#include "common/base/server.h"

class Session;
class SessionMgr;
class ISessionFilter;

enum ServerType : uint16_t;
union MessageID;

enum SessionType : uint16_t;

struct ServerNetInfo;

/**
 * @desc 客户端与LoginGate服务器连接会话的管理类
 * @auth Qiwei.Gu
 * @date 2015-03-12 21:35:48
 */
class SessionMgr : public IManager, public IServer, public std::enable_shared_from_this<SessionMgr>
{
public:
    explicit SessionMgr(boost::asio::io_service& ios, ServerType serverType);

    /**
     * @desc 拼接SessionID
     * @auth Qiwei.Gu
     * @date 2015-04-14 16:58:10
     */
    static uint64_t makeSessionID(ServerType serverType, SessionType sessionType, int16_t serverID);


    /**
     * @desc 初始化类，包括配置
     * @auth Qiwei.Gu
     * @date 2015-03-12 21:47:35
     */
    virtual bool init();

    /**
     * @desc 发送消息
     * @auth Qiwei.Gu
     * @date 2015-03-21 18:03:44
     */
    virtual bool send(MessageID msgID,
                      uint32_t sessionID,
                      const google::protobuf::Message& msg);

    /**
     * @desc 添加会话
     * @auth Qiwei.Gu
     * @date 2015-03-26 23:25:05
     */
    bool addSession(const std::shared_ptr<Session>& session);

    /**
     * @desc 移除连接会话
     * @auth Qiwei.Gu
     * @date 2015-03-21 18:04:01
     */
    bool removeSession(const std::shared_ptr<Session>& session);

    /**
     * @desc 查询本地会话
     * @auth Qiwei.Gu
     * @date 2015-04-07 15:15:39
     */
    std::shared_ptr<Session> getListenSession(ServerType serverType, SessionType sessionType, int16_t serverID);


    /**
     * @desc 查询监听会话
     * @auth Qiwei.Gu
     * @date 2015-04-21 16:44:07
     */
    std::map<uint16_t, std::shared_ptr<Session>> getListenSessions(ServerType serverType,
                                                                   SessionType sessionType);

    /**
     * @desc 查询远程连接过来的络连接会话,
     * @retrun 连接会话
     * @auth Qiwei.Gu
     * @date 2015-04-04 12:25:53
     */
    std::shared_ptr<Session> getAcceptedSession(uint64_t handle);


    /**
     * @desc 查询主动连接的会话
     * @param serverType 服务器类型
     * @param sessionType 会话类型
     * @auth Qiwei.Gu
     * @date 2015-04-21 14:48:02
     */
    void getConnSessions(ServerType serverType, SessionType sessionType,
                         std::vector<std::shared_ptr<Session> >& sessions);

    /**
     * @desc 添加会话过滤器
     * @auth Qiwei.Gu
     * @date 2015-04-22 14:43:48
     */
    void addFilter(const std::shared_ptr<ISessionFilter>& filter)
    {
        filters_.push_back(filter);
    }

    /**
     * @desc 获得所有过滤器
     * @auth Qiwei.Gu
     * @date 2015-04-22 14:46:59
     */
    const std::list<std::shared_ptr<ISessionFilter>>& getFilters() { return filters_; }

private:
    /**
     * @desc 开始接受网络连接
     * @auth Qiwei.Gu
     * @date 2015-03-21 18:04:52
     */
    void startAccept();

    /**
     * @desc 初始化监听连接
     * @auth Qiwei.Gu
     * @date 2015-04-04 13:43:59
     */
    bool initListenNet(const std::shared_ptr<ServerNetInfo>& netInfo);

    /**
     * @desc 初始化主动连接
     * @auth Qiwei.Gu
     * @date 2015-04-04 13:43:59
     */
    bool initConnNet(const std::shared_ptr<ServerNetInfo>& netInfo);

    /**
     * @desc only for test print local localSessions_
     * @auth Qiwei.Gu
     * @date 2015-04-18 16:18:28
     */
    void printListenSessions();

    void printAcceptedSessions();

    void printConnSessions();

private:
    ServerType serverType_;  // 服务器类型
    std::mutex mutex_;

    // <(ServerType, sessionType, serverID), session> 监听的连接会话
    std::map<uint64_t, std::shared_ptr<Session>> listenSessions_;

    // <handle, session> 对方连接过来的会话
    std::map<uint64_t, std::shared_ptr<Session>> acceptedSessions_;

    // 主动连接的会话
    std::map<std::pair<ServerType, SessionType>, std::map<uint64_t, std::shared_ptr<Session>>> connSessions_;

    std::list<std::shared_ptr<ISessionFilter>> filters_;
};

#endif // __NET_SERVER_H__
